
package roborally.model;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;

import roborally.IFacade;
import roborally.exceptions.EndOfProgramException;
import roborally.exceptions.IllegalMoveException;
import roborally.exceptions.InvalidPositionException;
import roborally.exceptions.PositionSharingException;
import roborally.exceptions.ProgramParsingError;
import roborally.program.Program;

/**
 * A class for connecting the RoboRally-code with the user interface.
 * 
 * @version  1.0
 * @author  Pieter Robberechts	(1e Bach Informatica)
 * @author	Jeroen Sanders		(1e Bach Informatica)
 *  
 */
public class Facade implements IFacade<Board, Robot, Wall, Battery, RepairKit, SurpriseBox> {

	/**
	 * Create a new board with the given width and height. 
	 * 	Return null if the given width or height is invalid.
	 * 
	 * @param	width
	 * 			The width for the new board.
	 * @param	height
	 * 			The height for the new board.
	 * @return	...
	 * 			| result == new Board(width, height)
	 */
	@Override
	public Board createBoard(long width, long height) {
		try{
			return new Board(width, height);
		}catch(IllegalArgumentException e){
			System.err.println(e.getMessage());
		}
		return null;
	}

	/**
	 * Merge board 1 and board 2.
	 * 
	 * @param	board1
	 * 			The first board to merge.
	 * @param	board2
	 * 			The second board to merge.
	 * @effect	...
	 * 			| board1.merge(board2)
	 */
	@Override
	public void merge(Board board1, Board board2) {
		try{
			board1.merge(board2);
		}catch(IllegalArgumentException e){
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Create a new battery with given initial energy and weight. 
	 * 	Return null if the given parameters are invalid (e.g. negative weight). 
	 * 
	 * @param	initialEnergy
	 * 			The initial amount of energy for this new battery.
	 * @param	weight
	 * 			The weight for this new battery.
	 * @return	...
	 * 			| result == new Battery(new EnergyAmount(initialEnergy), new Weight(weight))
	 */
	@Override
	public Battery createBattery(double initialEnergy, int weight) {
		Battery battery = new Battery(new EnergyAmount(initialEnergy), new Weight(weight));
		if(battery.canHaveAsEnergy(new EnergyAmount(initialEnergy)) && battery.canHaveAsWeight(new Weight(weight)))	
			return battery;
		else
			return null;
	}

	/**
	 * Put a battery at a given position, on a given board (if possible).
	 * 
	 * @param	board
	 * 			The board to put the battery on.
	 * @param	x
	 * 			The x-coordinate of the position to put the battery at.
	 * @param	y
	 * 			The y-coordinate of the position to put the battery at.
	 * @param	battery
	 * 			The battery to put on a given board, at a given position.
	 * @effect	...
	 * 			| board.putElement(new Position(x,y), battery)
	 */
	@Override
	public void putBattery(Board board, long x, long y, Battery battery) {
		try {
			board.putElement(new Position(x,y), battery);
		} catch(IllegalStateException e) {
			System.err.println(e.getMessage());
		} catch (IllegalArgumentException e) {
			System.err.println(e.getMessage());
		} catch (InvalidPositionException e) {
			System.err.println(e.getMessage());
		} catch (PositionSharingException e) {
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Return the x-coordinate of a given battery.
	 * 
	 * @param 	battery
	 * 			The battery which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(battery.getPosition() != null)
	 * 			|	then result == battery.getPosition().getX()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getBatteryX(Battery battery) {
		if(battery.getPosition() == null) {
			System.err.println("The battery is not placed on a board!");
			return -1;
		}	
		return battery.getPosition().getX();	
	}

	/**
	 * Return the y-coordinate of a given battery.
	 * 
	 * @param 	battery
	 * 			The battery which y-coordinate should be returned.
	 * @return 	...
	 * 			| if(battery.getPosition() != null)
	 * 			|	then result == battery.getPosition().getY()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getBatteryY(Battery battery) {
		if(battery.getPosition() == null) {
			System.err.println("The battery is not placed on a board!");
			return -1;
		}
		return battery.getPosition().getY();	
	}

	/** 
	 * Create a new Robot with a given orientation and energy.
	 * 	Return null if the given parameters are invalid (e.g. negative energy). 
	 * 
	 * @param	orientation
	 *  		The initial orientation for this new robot.
	 * @param	initialEnergy
	 *  		The initial amount of energy for this new robot.
	 * @return	...
	 * 			| result == new Robot(Orientation.getConstant(orientation), new EnergyAmount(initialEnergy));
	 */
	@Override
	public Robot createRobot(int orientation, double initialEnergy) {
		Orientation orientationConstant = Orientation.getConstant(orientation);
		EnergyAmount energyAmount = new EnergyAmount(initialEnergy);
		Robot robot = new Robot(orientationConstant, energyAmount);
		
		if(robot.canHaveAsOrientation(orientationConstant) && robot.canHaveAsEnergy(energyAmount))
			return robot;
		else
			return null;
	}

	/**
	 * Put a given robot at a given position, on a given board (if possible).
	 * 
	 * @param	board
	 * 			The board to put the robot on.
	 * @param	x
	 * 			The x-coordinate of the position to put the robot at.
	 * @param	y
	 * 			The y-coordinate of the position to put the robot at.
	 * @param	robot
	 * 			The robot to put on a given position, on a given board.
	 * @effect	...
	 * 			| board.putElement(new Position(x,y), robot) 
	 */
	@Override
	public void putRobot(Board board, long x, long y, Robot robot) {
		try {
			board.putElement(new Position(x,y), robot);
		} catch (IllegalStateException e) {
			System.err.println(e.getMessage());
		} catch (IllegalArgumentException e) {
			System.err.println(e.getMessage());
		} catch (InvalidPositionException e) {
			System.err.println(e.getMessage());
		} catch (PositionSharingException e) {
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Return the x-coordinate of a given robot.
	 * 
	 * @param 	robot
	 * 			The robot which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(robot.getPosition() != null)
	 * 			|	then result == robot.getPosition().getX()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getRobotX(Robot robot) {
		if(robot.getPosition() == null) {
			System.err.println("The robot is not placed on a board!");
			return -1;
		}
		return robot.getPosition().getX();
	}

	/**
	 * Return the y-coordinate of a given robot.
	 * 
	 * @param 	robot
	 * 			The robot which y-coordinate should be returned.
	 * @return 	...
	 * 			| if(robot.getPosition() != null)
	 * 			|	then result == robot.getPosition().getY()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getRobotY(Robot robot) {
		if(robot.getPosition() == null) {
			System.err.println("The robot is not placed on a board!");
			return -1;
		}
		return robot.getPosition().getY();
	}

	/**
	 * Return the orientation (either 0, 1, 2 or 3) of a given robot.
	 * 
	 * @param 	robot
	 * 			The robot which orientation should be returned.
	 * @return	...
	 * 			| result == robot.getOrientation().getNumber()
	 */
	@Override
	public int getOrientation(Robot robot) {
		return robot.getOrientation().getNumber();
	}

	/**
	 * Return the current amount of energy in watt-second of a given robot.
	 * 
	 * @param 	robot
	 * 			The robot which amount of energy should be returned.
	 * @return	...
	 * 			| result == robot.getEnergy().getAmountInUnits()
	 */
	@Override
	public double getEnergy(Robot robot) {
		return robot.getEnergy().getAmountInUnits();
	}

	/**
	 * Move a given robot one step in its current direction if the robot has sufficient energy. 
	 * 	Do not modify the state of the robot if it has insufficient energy.
	 * 
	 * @param 	robot
	 * 			The robot which should be moved.
	 * @effect	...
	 * 			| if(! robot.getEnergy().lessThan(robot.getEnergyRequiredToMove()) )
	 * 			| 	then robot.move()
	 */	
	@Override
	public void move(Robot robot) {
		if(! robot.getEnergy().lessThan(robot.getEnergyRequiredToMove()) ) {
			try {
				robot.move();
			} catch (IllegalMoveException e) {
				System.err.println(e.getMessage());
			} catch (IllegalStateException e) {
				System.err.println(e.getMessage());
			}
		}
	}

	/**
	 * Turn a given robot 90 degrees in clockwise direction if the robot has sufficient energy. 
	 * 	Do not modify the state of the robot if it has insufficient energy.
	 * 
	 * @param 	robot
	 * 			The robot which should be turned.
	 * @efect	...
	 * 			| if(! robot.getEnergy().lessThan(Robot.getEnergyRequiredToTurn()))	
	 * 			| 	then robot.turn(Direction.CLOCKWISE)
	 */
	@Override
	public void turn(Robot robot) {
		if(! robot.getEnergy().lessThan(Robot.getEnergyRequiredToTurn())) {
			robot.turn(Direction.CLOCKWISE);
		}
	}

	/**
	 * Return whether your implementation of <code>isMinimalCostToReach</code> takes into account other robots, walls and turning (required to score 17+). The return
	 * value of this method determines the expected return value of <code>isMinimalCostToReach</code> in the test suite.
	 * 
	 * This method must return either 0 or 1.
	 */
	@Override
	public int isMinimalCostToReach17Plus() {
		return 1;
	}

	/**
	 * Return the minimal amount of energy required for a given robot to reach a position (x, y),
	 * taking into account the robot's current load and energy level.
	 * 
	 * @param	robot
	 * 			The robot for which the minimal cost to reach the given position should be calculated.
	 * @param	x
	 * 			The x-coordinate of the position for which the minimal cost to reach it with the given robot should be calculated.
	 * @param	y
	 * 			The y-coordinate of the position for which the minimal cost to reach it with the given robot should be calculated.
	 * @return	Return -1 if robot is not placed on a board or if the robot has insufficient energy to reach (x, y).
	 */
	@Override
	public double getMinimalCostToReach(Robot robot, long x, long y) {
		try {
			return robot.getMinimalCostToReach(new Position(x,y));
		} catch (Exception e) {
			return -1;
		}
	}
	
	/**
	 * Return whether your implementation of <code>moveNextTo</code> takes into account other robots, walls and the fact that turning consumes energy (required to score 18+). The return
	 * value of this method determines the expected effect of <code>moveNextTo</code> in the test suite.
	 * 
	 * This method must return either 0 or 1.
	 */
	@Override
	public int isMoveNextTo18Plus() {
		return 1;
	}

	/**
	 * Move a given robot as close as possible (expressed as the manhattan distance) to second given robot. 
	 * 	If multiple optimal (in distance) solutions exist, the solution that requires the least amount of total energy is selected.  
	 * 	If both robots are not located on the same board, their states remain unchanged.
	 * 
	 * @param	robot
	 * 			The first robot which is involved in the movement.
	 * @param	other
	 * 			The second robot which is involved in the movement.
	 */
	@Override
	public void moveNextTo(Robot robot, Robot other) {
		try {
			robot.moveNextTo(other);
		} catch(Exception e) {
			System.err.println("Exception: " + e.getMessage());
		}
	}

	/**
	 * Make a given robot shoot in the orientation it is currently facing (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should shoot.
	 * @effect	...
	 * 			| if(! robot.getEnergy().lessThan(robot.getEnergyRequiredToShoot()))
	 *			|	then robot.shoot()
	 */
	@Override
	public void shoot(Robot robot) throws UnsupportedOperationException {
		if(! robot.getEnergy().lessThan(robot.getEnergyRequiredToShoot()))
			robot.shoot();
	}

	/**
	 * Create a new wall.
	 * 
	 * @return	...
	 * 			| result == new Wall()
	 */
	@Override
	public Wall createWall() throws UnsupportedOperationException {
		return new Wall();
	}

	/**
	 * Put a given wall at a given position, on a given board (if possible).
	 * 
	 * @param	board
	 * 			The board to put the wall on.
	 * @param	x
	 * 			The x-coordinate of the position to put the wall at.
	 * @param	y
	 * 			The y-coordinate of the position to put the wall at.
	 * @param	wall
	 * 			The wall to put on a given position, on a given board.
	 * @effect	...
	 * 			| board.putElement(new Position(x,y), battery)
	 */
	@Override
	public void putWall(Board board, long x, long y, Wall wall) throws UnsupportedOperationException {
		try {
			board.putElement(new Position(x,y), wall);
		} catch (IllegalArgumentException e) {
			System.err.println(e.getMessage());
		} catch (InvalidPositionException e) {
			System.err.println(e.getMessage());
		} catch (PositionSharingException e) {
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Return the x-coordinate of a given wall.
	 * 
	 * @param 	wall
	 * 			The wall which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(wall.getPosition() != null)
	 * 			|	then result == wall.getPosition().getX()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getWallX(Wall wall) throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
		if(wall.getPosition() == null) {
			System.err.println("The wall is not placed on a board!");
			return -1;
		}
		return wall.getPosition().getX();
	}

	/**
	 * Return the y-coordinate of a given wall.
	 * 
	 * @param 	wall
	 * 			The wall which y-coordinate should be returned.
	 * @return 	...
	 * 			| if(wall.getPosition() != null)
	 * 			|	then result == wall.getPosition().getY()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getWallY(Wall wall) throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
		if(wall.getPosition() == null) {
			System.err.println("The wall is not placed on a board!");
			return -1;
		}
		return wall.getPosition().getY();
	}

	/**
	 * Return a set containing all robots on a given board.
	 * 
	 * @param	board
	 * 			The board from which a set of all robots it contains should be returned.
	 * @return	...
	 * 			| board.getElements(Robot.class)
	 */
	@Override
	public Set<Robot> getRobots(Board board) {
		return board.getElements(Robot.class);
	}

	/**
	 * Return a set containing all batteries on a given board.
	 * 
	 * @param	board
	 * 			The board from which a set of all batteries it contains should be returned.
	 * @return	...
	 * 			result == board.getElements(Battery.class)
	 */
	@Override
	public Set<Battery> getBatteries(Board board) {
		return board.getElements(Battery.class);
	}

	/**
	 * Return a set containing all walls on a given board.
	 * 
	 * @param	board
	 * 			The board from which a set of all walls it contains should be returned.
	 * @return	...
	 * 			| result == board.getElements(Wall.class)
	 */
	@Override
	public Set<Wall> getWalls(Board board) throws UnsupportedOperationException {
		return board.getElements(Wall.class);
	}

	/**
	 * Create a new Repair Kit with given repair amount and weight. 
	 * Return null if the given parameters are invalid (e.g. negative weight). 
	 * 
	 * @param	repairAmount
	 * 			The initial amount of repair energy for this new battery.
	 * @param	weight
	 * 			The weight for this new battery.
	 * @return	...
	 * 			| result == new RepairKit(new EnergyAmount(repairAmount), new Weight(weight))
	 */
	@Override
	public RepairKit createRepairKit(double repairAmount, int weight) {
		RepairKit repairKit = new RepairKit(new EnergyAmount(repairAmount),new Weight(weight));
		if(repairKit.canHaveAsEnergy(new EnergyAmount(repairAmount)) && repairKit.canHaveAsWeight(new Weight(weight)))	
			return repairKit;
		else
			return null;
	}

	/**
	 * Put a repair kit at a given position, on a given board (if possible).
	 * 
	 * @param	board
	 * 			The board to put the repair kit on.
	 * @param	x
	 * 			The x-coordinate of the position to put the repair kit at.
	 * @param	y
	 * 			The y-coordinate of the position to put the repair kit at.
	 * @param	repairKit
	 * 			The repair kit to put on a given board, at a given position.
	 * @effect	...
	 * 			| board.putElement(new Position(x,y), repairKit)
	 */
	@Override
	public void putRepairKit(Board board, long x, long y, RepairKit repairKit) {
		try {
			board.putElement(new Position(x,y), repairKit);
		} catch (IllegalArgumentException e) {
			System.err.println(e.getMessage());
		} catch (InvalidPositionException e) {
			System.err.println(e.getMessage());
		} catch (PositionSharingException e) {
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Return the x-coordinate of a given repair kit.
	 * 
	 * @param 	repairKit
	 * 			The repair kit which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(repairKit.getPosition() != null)
	 * 			|	then result == repairKit.getPosition().getX()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getRepairKitX(RepairKit repairKit) throws IllegalStateException {
		if(repairKit.getPosition() == null) {
			System.err.println("The repairKit is not placed on a board!");
			return -1;
		}
		return repairKit.getPosition().getX();
	}

	/**
	 * Return the y-coordinate of a given repair kit.
	 * 
	 * @param 	repairKit
	 * 			The repair kit which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(repairKit.getPosition() != null)
	 * 			|	then result == repairKit.getPosition().getY()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getRepairKitY(RepairKit repairKit) throws IllegalStateException {
		if(repairKit.getPosition() == null) {
			System.err.println("The repairKit is not placed on a board!");
			return -1;
		}
		return repairKit.getPosition().getY();
	}

	/**
	 * Create a new Surprise Box with given repair amount and weight. 
	 * Return null if the given parameters are invalid (e.g. negative weight). 
	 * 
	 * @param	weight
	 * 			The weight for this new battery.
	 * @return	...
	 * 			| result == new RepairKit(new EnergyAmount(repairAmount), new Weight(weight))
	 */
	@Override
	public SurpriseBox createSurpriseBox(int weight) {
		SurpriseBox surpriseBox = new SurpriseBox(new Weight(weight));
		if(surpriseBox.canHaveAsWeight(new Weight(weight)))
			return surpriseBox;
		else
			return null;
	}

	/**
	 * Put a Surprise Box at a given position, on a given board (if possible).
	 * 
	 * @param	board
	 * 			The board to put the repair kit on.
	 * @param	x
	 * 			The x-coordinate of the position to put the repair kit at.
	 * @param	y
	 * 			The y-coordinate of the position to put the repair kit at.
	 * @param	surpriseBox
	 * 			The surprise box to put on a given board, at a given position.
	 * @effect	...
	 * 			| board.putElement(new Position(x,y), surpriseBox)
	 */
	@Override
	public void putSurpriseBox(Board board, long x, long y,
			SurpriseBox surpriseBox) {
		try {
			board.putElement(new Position(x,y), surpriseBox);
		} catch (IllegalArgumentException e) {
			System.err.println(e.getMessage());
		} catch (InvalidPositionException e) {
			System.err.println(e.getMessage());
		} catch (PositionSharingException e) {
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Return the x-coordinate of a given surprise box.
	 * 
	 * @param 	surpriseBox
	 * 			The surprise box which x-coordinate should be returned.
	 * @return 	...
	 * 			| if(surpriseBox.getPosition() != null)
	 * 			|	then result == surpriseBox.getPosition().getX()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getSurpriseBoxX(SurpriseBox surpriseBox)
			throws IllegalStateException {
		if(surpriseBox.getPosition() == null) {
			System.err.println("The repairKit is not placed on a board!");
			return -1;
		}
		return surpriseBox.getPosition().getX();
	}

	/**
	 * Return the y-coordinate of a given surprise box.
	 * 
	 * @param 	surpriseBox
	 * 			The surprise box which y-coordinate should be returned.
	 * @return 	...
	 * 			| if(surpriseBox.getPosition() != null)
	 * 			|	then result == surpriseBox.getPosition().getY()
	 * 			| else
	 * 			|	then result == -1
	 */
	@Override
	public long getSurpriseBoxY(SurpriseBox surpriseBox)
			throws IllegalStateException {
		if(surpriseBox.getPosition() == null) {
			System.err.println("The repairKit is not placed on a board!");
			return -1;
		}
		return surpriseBox.getPosition().getY();
	}

	/**
	 * Make a given robot pick up a given battery (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should pick up the given battery.
	 * @param	battery
	 * 			The battery which should be picked up.
	 * @effect	...
	 * 			| robot.pickUp(battery)
	 */
	@Override
	public void pickUpBattery(Robot robot, Battery battery) {
		robot.pickUp(battery);
	}

	/**
	 * Make a given robot use a given battery (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should use the given battery.
	 * @param	battery
	 * 			The battery which should be used.
	 * @effect	...
	 * 			| robot.use(battery)
	 */
	@Override
	public void useBattery(Robot robot, Battery battery) {
		robot.use(battery);
	}

	/**
	 * Make a given robot drop a given battery (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should drop the given battery.
	 * @param	battery
	 * 			The battery which should be dropped.
	 * @effect	...
	 * 			| robot.drop(battery)
	 */
	@Override
	public void dropBattery(Robot robot, Battery battery) {
		robot.drop(battery);
	}

	/**
	 * Make a given robot pick up a given repair kit (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should pick up the given repair kit.
	 * @param	repairKit
	 * 			The repair kit which should be picked up.
	 * @effect	...
	 * 			| robot.pickUp(repairKit)
	 */
	@Override
	public void pickUpRepairKit(Robot robot, RepairKit repairKit) {
		robot.pickUp(repairKit);
	}

	/**
	 * Make a given robot use a given repair kit (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should use the given repair kit.
	 * @param	repairKit
	 * 			The repair kit which should be used.
	 * @effect	...
	 * 			| robot.use(repairKit)
	 */
	@Override
	public void useRepairKit(Robot robot, RepairKit repairKit) {
		robot.use(repairKit);
	}

	/**
	 * Make a given robot drop a given repair kit (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should drop the given repair kit.
	 * @param	repairKit
	 * 			The repair kit which should be dropped.
	 * @effect	...
	 * 			| robot.drop(repairKit)
	 */
	@Override
	public void dropRepairKit(Robot robot, RepairKit repairKit) {
		robot.drop(repairKit);
	}

	/**
	 * Make a given robot pick up a given surprise box (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should pick up the given surprise box.
	 * @param	surpriseBox
	 * 			The surprise box which should be picked up.
	 * @effect	...
	 * 			| robot.pickUp(surpriseBox)
	 */
	@Override
	public void pickUpSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.pickUp(surpriseBox);
	}

	/**
	 * Make a given robot use a given surprise box (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should use the given surprise box.
	 * @param	surpriseBox
	 * 			The surprise box which should be used.
	 * @effect	...
	 * 			| robot.use(surpriseBox)
	 */
	@Override
	public void useSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.use(surpriseBox);
	}

	/**
	 * Make a given robot drop a given surprise box (if possible).
	 * 
	 * @param	robot
	 * 			The robot which should drop the given surprise box.
	 * @param	surpriseBox
	 * 			The surprise box which should be dropped.
	 * @effect	...
	 * 			| robot.drop(surpriseBox)
	 */
	@Override
	public void dropSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.drop(surpriseBox);
	}

	/**
	 * Transfers all the items from one robot to a robot standing next to this robot.
	 * 
	 * @param	from
	 * 			The robot that will transfer items.
	 * @param	to
	 * 			The robot that will receive the transfered items.
	 * 
	 * @effect	...
	 * 			| from.transferItems(to)
	 * 
	 */
	@Override
	public void transferItems(Robot from, Robot to) {
		try {
			from.transferItems(to);
		} catch (IllegalArgumentException e) {
			System.err.println("IllegalArgumentException:" + e.getMessage());
		}
	}

	/**
	 * Return a set containing all repair kits on a given board.
	 * 
	 * @param	board
	 * 			The board from which a set of all repair kits it contains should be returned.
	 * @return	...
	 * 			result == board.getElements(RepairKit.class)
	 */
	@Override
	public Set<RepairKit> getRepairKits(Board board) {
		return board.getElements(RepairKit.class);
	}

	/**
	 * Return a set containing all surprise boxes on a given board.
	 * 
	 * @param	board
	 * 			The board from which a set of all surprise boxes it contains should be returned.
	 * @return	...
	 * 			result == board.getElements(SurpriseBox.class)
	 */
	@Override
	public Set<SurpriseBox> getSurpriseBoxes(Board board) {
		return board.getElements(SurpriseBox.class);
	}

	/**
	 * Load the program stored at a given path and assign it to a given robot.
	 * 
	 * @effect	...
	 * 			| robot.setProgram(Program.loadFromFile(path))
	 * @return	Return '0' if the operation completed successfully; 
	 * 			otherwise, return a negative number.
	 */
	@Override
	public int loadProgramFromFile(Robot robot, String path) {
		try {
			Program program = Program.loadFromFile(path);
			robot.setProgram(program);
		} catch (FileNotFoundException e) {
			return -1;
		} catch (ProgramParsingError e) {
			return -2;
		} catch (IOException e) {
			return -3;
		} catch (IllegalStateException e) {
			return -4;
		}
		return 0;
	}

	/**
	 * Save the program of a given robot in a file at a given path.
	 * 
	 * @effect	...
	 * 			| robot.getProgram().saveToFile(path)
	 * @return	Return '0' if the operation completed successfully; 
	 * 			otherwise, return a negative number.
	 */
	@Override
	public int saveProgramToFile(Robot robot, String path) {
		try {
			robot.getProgram().saveToFile(path);
		} catch (IOException e) {
			return -1;
		}
		return 0;
	}

	/**
	 * Pretty print the program of a given robot via a given writer-object.
	 * 
	 * @param	robot
	 * 			The robot from which the program should be printed.
	 * @param	writer
	 * 			Print the program via this writer-object.
	 * @effect	...
	 * 			| writer.write(robot.getProgram().prettyFormat())
	 */
	@Override
	public void prettyPrintProgram(Robot robot, Writer writer) {
		try {
			writer.write(robot.getProgram().prettyFormat());
		} catch (IOException e) {
			System.err.println("IOException:" + e.getMessage());
		}
	}

	/**
	 * Execute n basic steps in the program of a given robot.
	 * 
	 * @param	robot
	 * 			Execute the program of this robot.
	 * @param	n
	 * 			The amount of steps which should be executed.
	 * @effect	...
	 * 			| for each i in n : 
	 * 			|	robot.executeNextBasicCommand()
	 */
	@Override
	public void stepn(Robot robot, int n) {
		try {
			for (int i = 0; i < n; i++) {
				robot.executeNextBasicCommand();
			}
		} catch (EndOfProgramException e) {
			System.err.println("End of program.");
		} catch (IllegalStateException e) {
			System.err.println(e.getMessage());
		} catch (Exception e) {
			System.err.println("Invalid program instruction!");
		}
		
	}

}
